package us.versus.them.bitly;

import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.filters.BlurFilter;

class Light {
	public var size : Int;
	public var position:Point;
	public var velocity:Point;
	public var map:BitmapData;

	public function new( ?size:Int ) {
		this.size = if ( null == size ) { 128; } else { size; }
		position = new Point( 0, 0 );
		velocity = new Point( 1, 1 );
		map = new BitmapData( size, size );
		for ( y in 0 ... this.size ) {
			var yo = ( y - this.size / 2 ) / ( this.size / 2 );
			yo = 1 - ( yo * yo );
			for ( x in 0 ... this.size ) {
				var xo = ( x - this.size / 2 ) / ( this.size / 2 );
				xo = 1 - ( xo * xo );
				map.setPixel( x, y, Math.floor( 255 * xo * yo * xo * yo ) );
			}
		}
	}

	public function displace( x, y, dx, dy, color ) {
		var xo = Math.floor( x - position.x + dx + size / 2);
		var yo = Math.floor( y - position.y + dy + size / 2);
		var scale = 0.0;
		if ( 
			   xo > -1 && xo < size 
			&& yo > -1 && yo < size 
		) {
			scale = map.getPixel( xo, yo ) / 200;
		}

		color = Math.floor( color * scale );
		//color = Math.floor( color + scale );
		if ( color > 255 ) color = 255;
		return App.rgb( 64 - color / 4, color / 2, color );
	}

	public function move( w:Int, h:Int ) {
		var x = position.x + velocity.x;
		var y = position.y + velocity.y;
		if ( x < 0 || x >= w  ) {
			velocity.x *= -1;
			x = position.x;
		} else {
			position.x = x;
		}
		if ( y < 0 || y >= h  ) {
			velocity.y *= -1;
		} else {
			position.y = y;
		}
	}
}

/**
 *
 * This is a pretty silly way to do this... Need to see how to do it with filters:
 * http://www.unitzeroone.com/blog/2006/03/28/flash-8-example-3d-bumpmapping-using-filters-source-included/
 *
 *
 *
 */
class Bumpin implements Bitter {
	var light:Light;

	public function new() {
		light = new Light( 128 );
	}

	public function distress( bitmapData:BitmapData ) {
		bitmapData.noise( 128, 64, 192, 4, true );
	}

	public function smoothCopy( w:Int, h:Int, bitmapData:BitmapData, tmp:BitmapData ) : Void {
		tmp.applyFilter( 
			bitmapData
			, new Rectangle( 0, 0, w, h )
			, new Point( 0, 0 )
			, new BlurFilter( 1, 1, 1 )
		);
	}

	public function reset( w:Int, h:Int, bitmapData:BitmapData, tmp:BitmapData ) : Void {
		distress( bitmapData );
		smoothCopy( w,h, bitmapData, tmp );
		graySpread( w, h, tmp );
		light.position = new Point( w / 2, h / 2 );
	}

	public function graySpread( w:Int, h:Int, tmp:BitmapData ) {
		var min = 255;
		var max = 0;
		for ( y in 0 ... h ) {
			for ( x in 0 ... w ) {
				var c = tmp.getPixel( x, y );
				c = Math.floor(
					(
						  ( c >> 16 & 0xFF ) 
						+ ( c >>  8 & 0xFF ) 
						+ ( c >>  0 & 0xFF ) 
					) / 3
				);
				c = 0xFF & tmp.getPixel( x, y );
				tmp.setPixel( x, y, c&0xff );
				if ( c < min ) min = c;
				if ( c > max ) max = c;
			}
		}
/*
		var mag = 255 / ( max - min );
		for ( y in 0 ... h ) { 
			for ( x in 0 ... w ) {
				var c = Math.floor( ( tmp.getPixel( x, y ) - min ) * 255 );
				tmp.setPixel( x, y, c&0xFF );
			}
		}
*/
	}

	public function loop( w:Int, h:Int, bitmapData:BitmapData, tmp:BitmapData ) : Bool {
		if ( !true ) { 
			bitmapData.copyPixels( 
				light.map, new Rectangle( 0, 0, light.size, light.size ), new Point( 0, 0 ) 
			);
		} else {
			for ( y in 0 ... h ) {
				for ( x in 0 ... w ) {
					bitmapData.setPixel(
							x
							, y
							, light.displace( 
								x
								, y
								, tmp.getPixel( x, y ) - tmp.getPixel( x - 1, y )
								, tmp.getPixel( x, y ) - tmp.getPixel( x, y - 1 )
								, tmp.getPixel( x, y )
								)
							);
				}
			}
		}
		bitmapData.setPixel( Math.floor( light.position.x ), Math.floor( light.position.y ), 0xFF0000 );
		light.move( w, h );
		return false;
	}
}
